package vois

import (
	"encoding/xml"
	"fmt"
	"strings"

	"code.google.com/awwwe-browser/data"
)

// Parse <navigation>...</navigation> tagss in an atom feed.
func processAtomNavigation(dec *xml.Decoder, e xml.StartElement) (*VOISContent, error) {
	var vc *VOISContent
	var err error
	vc = newVOISContent()
	vc.ContentType = AtomContentType
	err = _processAtomNavigation(dec, vc)
	if err == nil {
		if len(vc.Title) == 0 {
			err = buildVOISError("missing <title> inside the <atom-navigation>...</atom-navigation> tags.")
		} else if len(vc.OnlySpeakAt) == 0 {
			err = buildVOISError("missing <entries-at> inside the <atom-navigation>...</atom-navigation> tags.")
		}
	}
	return vc, err
}

// Parse <navigation>...</navigation> tags in an atom feed.
func _processAtomNavigation(dec *xml.Decoder, vc *VOISContent) error {
	// description
	// condition
	// title
	// title-at
	// links-at
	// neverspeak-at
	var token xml.Token
	var err error
	var se xml.StartElement
	var cd xml.CharData
	var ee xml.EndElement
	var ok bool
	var s string
	for {
		token, err = dec.Token()
		if err != nil {
			return err
		}
		token = xml.CopyToken(token)
		// start element
		switch token.(type) {
		case xml.StartElement:
			se, ok = token.(xml.StartElement)
			if se.Name.Local == "condition" {
				// char vc
				token, err = dec.Token()
				if err != nil {
					return err
				}
				token = xml.CopyToken(token)
				cd, ok = token.(xml.CharData)
				if ok {
					// there is char vc
					s = data.BytesToUTF8StringTrim(cd)
					s = strings.Replace(s, "&gt;", ">", -1)
					vc.Condition = strings.Replace(s, "&lt;", "<", -1)
					// end tag
					token, err = dec.Token()
					if err != nil {
						return err
					}
				}
				// end tag
				ee, ok = token.(xml.EndElement)
				if ok == false {
					return buildVOISError("condition end tag out of place.")
				}
				if ee.Name.Local != "condition" {
					return buildVOISError(fmt.Sprintf("unmatched </%s>", ee.Name.Local))
				}
			} else if se.Name.Local == "is-main-content" {
				vc.IsMainContent = true
				// get the end tag
				token, err = dec.Token()
				if err != nil {
					return err
				}
				ee, ok = token.(xml.EndElement)
				if ok == false {
					return buildVOISError("token to end element error.")
				}
				if ee.Name.Local != "is-main-content" {
					return buildVOISError(fmt.Sprintf("unmatched </%s>", ee.Name.Local))
				}
			} else if se.Name.Local == "title" {
				// char vc
				token, err = dec.Token()
				if err != nil {
					return err
				}
				token = xml.CopyToken(token)
				cd, ok = token.(xml.CharData)
				if ok {
					// there is char vc
					vc.Title = data.BytesToUTF8StringTrim(cd)
					// end tag
					token, err = dec.Token()
					if err != nil {
						return err
					}
				}
				// end tag
				ee, ok = token.(xml.EndElement)
				if ok == false {
					return buildVOISError("title end element out of place.")
				}
				if ee.Name.Local != "title" {
					return buildVOISError(fmt.Sprintf("unmatched </%s>", ee.Name.Local))
				}
			} else if se.Name.Local == "entries-at" {
				// char vc
				token, err = dec.Token()
				if err != nil {
					return err
				}
				token = xml.CopyToken(token)
				cd, ok = token.(xml.CharData)
				if ok {
					// there is char vc
					vc.OnlySpeakAt = data.BytesToUTF8StringTrim(cd)
					// end tag
					token, err = dec.Token()
					if err != nil {
						return err
					}
				}
				// end tag
				ee, ok = token.(xml.EndElement)
				if ok == false {
					return buildVOISError("entries-at end element out of place.")
				}
				if ee.Name.Local != "entries-at" {
					return buildVOISError(fmt.Sprintf("unmatched </%s>", ee.Name.Local))
				}
			} else {
				return buildVOISError(fmt.Sprintf("<%s> not allowed inside <atom-navigation>...</atom-navigation> tags.", se.Name.Local))
			}
		case xml.EndElement:
			ee, ok = token.(xml.EndElement)
			if ee.Name.Local != "atom-navigation" {
				return buildVOISError(fmt.Sprintf("unmatched </%s>", ee.Name.Local))
			} else {
				return nil
			}
		case xml.CharData:
			// ignore white space between tags
		case xml.Comment:
			// ignore the comment
		case xml.ProcInst:
			return buildVOISError("Processing instruction inside <atom-navigation>...</atom-navigation> tags")
		case xml.Directive:
			return buildVOISError("Directive inside <atom-navigation>...</atom-navigation> tags")
		}
	}
	return err
}
